#include "sim.h"

float simclock = 0;
calendar calentry[THREAD_MAX];
int last_thread = -1;

void* scheduler(void *v) {
	pthread_t tid;
	//cout << "scheduler() is thread "<<pthread_self()<<endl;
	//cout<<"scheduler (thread "<<pthread_self()<<") starts running"<<endl;
	while(1) {
		if (last_thread != -1) {
			pthread_setschedprio(last_thread,MINPRIO);
		}
		//select the thread with earliest time stamp to run
		if( calentry[0].occtime != INF && calentry[0].pid != -1) {
			simclock = calentry[0].occtime;
			tid = calentry[0].pid;
			//cout << "Scheduler removes earliest thread "<<tid<<" from calendar at time "<<simclock<<endl;
			//remove the thread with earliest time stamp from the calendar
			int i;
			for(i = 0; i < THREAD_MAX - 1; i ++) {
				if (calentry[i+1].occtime != INF && calentry[i+1].pid != -1) {
					calentry[i].occtime = calentry[i+1].occtime;
					calentry[i].pid = calentry[i+1].pid;
					continue;
				}
				calentry[i].occtime = INF;
				calentry[i].pid = -1;
				break;
			}
			pthread_setschedprio(tid,MAXPRIO);
			cout <<"scheduler resumed thread "<<tid<<" at time "<<simclock<<endl;
		}
		sched_yield();
	}
}

void asim::create(void *funcname(void *v)) {
	pthread_t tid;
	int i, j;
	int policy = SCHED_FIFO;
	sched_param param;
	pthread_create(&tid, NULL, funcname, NULL);
	pthread_setschedparam (tid, policy, &param);
	pthread_setschedprio(tid, MINPRIO);
	cout<<"Thread "<<pthread_self()<<" creat thread "<<tid<<" to excecute cust() at time "<<(int)simclock<<endl;
	//insert the thread into calendar
	for (i = 0; i < THREAD_MAX; i ++) {
		if(simclock > calentry[i].occtime) {
			continue;
		}
		else {
			for (j = THREAD_MAX - 1; j > i; j --) {
				calentry[j].occtime = calentry[j-1].occtime;
				calentry[j].pid = calentry[j-1].pid;
			}
			calentry[i].occtime = simclock;
			calentry[i].pid = tid;
			break;
		}
	}
}

void asim::yield(int to_tid) {
	pthread_t tid = pthread_self();
	pthread_setschedprio(tid,MINPRIO);
	pthread_setschedprio((pthread_t)to_tid,MAXPRIO);
}

void asim::setpri(int set_tid, int pri) {
	pthread_t tid;
	if(set_tid = SELF) {
		tid = pthread_self();
	}
	else{
		tid = (pthread_t)set_tid;
	}
	pthread_setschedprio(tid,pri);
}

void asim::hold(float time) {
	float thread_time;
	int i, j;
	thread_time = simclock + time;
	//insert the thread back into calendar
	for (i = 0; i < THREAD_MAX; i ++) {
		if(thread_time > calentry[i].occtime) {
			continue;
		}
		else {
			for (j = THREAD_MAX - 1; j > i; j --) {
				calentry[j].occtime = calentry[j-1].occtime;
				calentry[j].pid = calentry[j-1].pid;
			}
			calentry[i].occtime = thread_time;
			calentry[i].pid = pthread_self();
			break;
		}
	}
	//yield to scheduler
	last_thread = pthread_self();
	cout<<"Thread "<<pthread_self()<<" holds "<<time<<endl;
	sched_yield();
}
